#!/usr/bin/python
# -*- coding: utf-8 -*-
# AUTHOR:   yemd
# FILENAME: py_redis_cache.py
# DESCRIBE: redis cache封装库
# CREATED:  2014-01-14 15:50
# MODIFIED: 2014-05-23 16:30

from __future__ import division

import sys
import inspect
import time
import datetime
import redis
import socket
from dm_py_util import *


RETRY_TIMEOUT_FACTOR = 5
RECONNECT_TIME = 30*2000000
#RECONNECT_TIME = 60*3

#redis命令重试次数(0、1,共两次)
RETRY_REDIS_COMMAND_EXECUTE_TIMES = 1


#
# Redis服务器结构体
#
class redis_server():
    def __init__(self,Host=None,Port=0,Timeout=-1,Passwd=None,Mark=-1):
        self._host = Host
        self._port = Port
        self._timeout = Timeout
        self._password = Passwd
        self._mark = Mark
        self._readonly = True          #服务器是否只读
        self._broken = True            #服务器是否挂了
        self._rediscontext = None      #redis连接句柄
        self._last_active_time = 0.0 
    
    def set_master(self):
        self._readonly = False

    def set_broken(self):
        self._broken = True

    def is_readonly(self):
        return self._readonly

    def active(self):
        self._last_active_time = time.time() 


####################
#
#封装redis库
#
#####################
class PY_Redis_Cache():
    def __init__(self):
        self.__redis_contexts = {}  #key: host+port value: redis
        self.__writer = redis_server()
        self.__readers = []
        self.__cluster = PY_Cluster_Stat_Manager()
        self.__retry_connect_times = 0        #reader_server重连上限
        self.__reader_use_times = 0           #reader_server使用次数
        self.__cn__ = self.__class__.__name__ #classname,for log debug
    
    def print_server(self):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            DEBUG_LOG(_fn_,"_reader_use_times",self.__reader_use_times)
            DEBUG_LOG(_fn_,"_retry_connect_times",self.__retry_connect_times)

            if self.__writer:
                DEBUG_LOG(_fn_,"-----------------writer_server_print-------------")
                DEBUG_LOG(_fn_,"host-port",self.__writer._host,self.__writer._port)
                DEBUG_LOG(_fn_,"timeout-mark",self.__writer._timeout,self.__writer._mark)
                DEBUG_LOG(_fn_,"password",self.__writer._password)
                DEBUG_LOG(_fn_,"readonly",self.__writer._readonly)
                DEBUG_LOG(_fn_,"broken",self.__writer._broken)
                DEBUG_LOG(_fn_,"last_active_time",self.__writer._last_active_time)
            
            for server in self.__readers:
                DEBUG_LOG(_fn_,"-----------------reader_server_print-------------")
                if server is None:
                    ERROR_LOG(_fn_,"server is None")
                    continue
                DEBUG_LOG(_fn_,"host-port",server._host,server._port)
                DEBUG_LOG(_fn_,"timeout-mark",server._timeout,server._mark)
                DEBUG_LOG(_fn_,"password",server._password)
                DEBUG_LOG(_fn_,"readonly",server._readonly)
                DEBUG_LOG(_fn_,"broken",server._broken)
                DEBUG_LOG(_fn_,"last_active_time",server._last_active_time)
            #打印服务器使用状态
            self.__cluster.print_list()
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))


    def init(self,config):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            cfgparser = PYC_ConfigParser(config)
            #timeout = int(cfgparser.get_config("cacheconfig","connecttimeout"))
            readernum = int(cfgparser.get_config("cacheconfig","readernum"))
            DEBUG_LOG(_fn_,"readernum",readernum)
            #writer_server config_init
            if self.__init_redis_server_config(cfgparser,\
                    "cache_writer",self.__writer,False)<0:
                ERROR_LOG(_fn_,":_writer error",config)
                return -1
            self.__writer.set_master()
            #reader_server config_init
            for i in range(0,readernum):
                reader = redis_server()
                seckey = "cache_reader_%d"%(i)
                if self.__init_redis_server_config(cfgparser,seckey,reader,True)<0:
                    ERROR_LOG(_fn_,":reader error",config);
                    return -1
                if reader._mark > 0:
                    self.__readers.append(reader)
            if not len(self.__readers):
                ERROR_LOG(_fn_,"no reader server can use")
                return -1
            #设置down服务器重连上限:即reids使用次数一旦未达到重连上限,执行up_servers#
            self.__retry_connect_times = RETRY_TIMEOUT_FACTOR * (readernum - 1)
            #连接所有redis服务器
            return self.__allconnect()
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return -1
    
    #
    #获取redis_server的基础配置信息
    #
    def __init_redis_server_config(self,cfgparser,section,server,read):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            DEBUG_LOG(_fn_,"start")
            server._host = cfgparser.get_config(section,"address")
            server._port = int(cfgparser.get_config(section,"port"))
            server._timeout = int(cfgparser.get_config(section,"timeout"))
            server._password = cfgparser.get_config(section,"passwd")
            if server._port <= 0 or server._timeout <= 0:
                return -1
            if not server._password:
                DEBUG_LOG(_fn_,"no password",section)
            DEBUG_LOG(_fn_,"host-port",server._host,server._port)
            if read:
                server._mark = int(cfgparser.get_config(section,"mark"))
                DEBUG_LOG(_fn_,"reader.mark",server._mark)
            return 0
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return -1

    def __allconnect(self):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            DEBUG_LOG(_fn_,"connect-writer------------------------------------");
            if self.__connect_server(self.__writer) < 0:
                ERROR_LOG(_fn_,"writer server connect error")
                return -1
            DEBUG_LOG(_fn_,"readers servernum",len(self.__readers))
            for i in range(0,len(self.__readers)):
                DEBUG_LOG(_fn_,"connect-reader--------------------------------");
                DEBUG_LOG(_fn_,"host-port",self.__readers[i]._host,self.__readers[i]._port)
                if self.__connect_server(self.__readers[i]) < 0:
                    ERROR_LOG(_fn_,"down a reader server:severnum",i)
                    self.__cluster.add_d_server(i,self.__readers[i]._mark)
                else:
                    self.__cluster.add_u_server(i,self.__readers[i]._mark)

            if self.__cluster.get_down_num() == len(self.__readers):
                ERROR_LOG(_fn_,"all reader server connect error!")
                return -1
            #self.__cluster.print_list() #server data print test
            DEBUG_LOG("-------------------all_init_finished-------------------")
            return 0
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return -1
    
    def __release_server(self,server):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            #DEBUG_LOG(_fn_,"start!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
            key = ':'.join([str(server._host), str(server._port)])
            self.__redis_contexts.pop(key, None)
            if server._rediscontext:
                #DEBUG_LOG(_fn_,":rediscontext exist, set it None!!!!!!!!!!")
                server._rediscontext = None
            server._broken = True
            server._last_active_time = 0.0
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))

    def __ping_server(self,server):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            if server._rediscontext is None:
                ERROR_LOG(_fn_,"rediscontext is None",server._host,server._port)
                return -1
            if not server._rediscontext.ping():
                raise Exception("ping return False!")
            #server.active() #是否需要设置新的活跃时间? 
            DEBUG_LOG(_fn_,":ping server success",server._host,server._port)
            return 0
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":redis error",str(e))
            return -1


    def __connect_server(self,server):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            key = ':'.join([str(server._host), str(server._port)])

            #复用redis连接
            if key in self.__redis_contexts and self.__redis_contexts[key]:
                INFO_LOG('redis server is already in connection pool', key)
                server._rediscontext = self.__redis_contexts[key]
            else:
                #释放server的所有上下文
                self.__release_server(server)

                #设置长链接选项
                keepalive_options = {}
                #1.开启keepalive属性
                keepalive_options[socket.SO_KEEPALIVE] = 1
                #2.若连接在60s内无任何数据往来,则进行探测
                keepalive_options[socket.TCP_KEEPIDLE] = 60
                #3.探测时发包的时间间隔为5s
                keepalive_options[socket.TCP_KEEPINTVL] = 5
                #4.探测次数
                keepalive_options[socket.TCP_KEEPCNT] = 3

                #构建redis连接上下文
                server._rediscontext = redis.Redis(host = server._host, 
                                        port = server._port,
                                        password = server._password,
                                        socket_timeout = server._timeout,
                                        socket_keepalive = True,
                                        socket_keepalive_options = keepalive_options)
                #redis.Redis仅是构造上下文,用ping查看是否能成功连接服务器
                if self.__ping_server(server) < 0:
                    ERROR_LOG(_fn_,"can't ping server",server._host,server._port)
                    return -1
                self.__redis_contexts[key] = server._rediscontext
            server._broken = False
            server.active()
            #DEBUG_LOG(_fn_,"new_active_time",server._last_active_time)
            return 0
        except Exception,e:
            server._rediscontext = None
            server._broken = True
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return -1

    #
    # 尝试恢复所有down掉的服务器
    #
    def __up_servers(self):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            #DEBUG_LOG(_fn_,"up_servers--------------------------------------")
            downnum = self.__cluster.get_down_num()
            DEBUG_LOG(_fn_,"server downnum",downnum)
            for i in range(0,downnum):
                selnum = self.__cluster.get_d_first()
                if selnum < 0:
                    DEBUG_LOG(_fn_,"no down server")
                    return
                if self.__connect_server(self.__readers[selnum]) < 0:
                    ERROR_LOG(_fn_,"reconnect server error:host-port",
                                        self.__readers[selnum]._host,
                                        self.__readers[selnum]._port)
                    self.__cluster.ignore_d_first()
                else:
                    DEBUG_LOG(_fn_,"connect suc:start up_d_first",selnum)
                    self.__cluster.up_d_first()
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return

    #
    # 选择一个可用的读服务器
    # 每次选择后都要查看是否有down服务器,有则需要增加_reader_use_times次数,
    # 并且每隔retry_connect_times重试次数之后尝试恢复所有down服务器
    # 目的：尽量保证随时有可用服务器,进行可读服务器的重连机制
    #
    def __select_reader(self):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            #DEBUG_LOG(_fn_,"start........................")
            retry = False
            selnum = -1
            while True:
                selnum = self.__cluster.select_num()
                #self.__cluster.print_list()
                if selnum < 0:
                    if retry:
                        break
                    retry = True
                    self.__up_servers()
                    self.__reader_use_times = 0
                else:
                    #DEBUG_LOG(_fn_,"suc get a server:selnum",selnum)
                    retry = False
                if not retry:
                    break
            if selnum < 0:
                ERROR_LOG(_fn_,"server are all down!!cannot restart")
                return None
            #有关down服务器恢复的工作:使用次数达到重试次数时恢复所有down服务器#
            downnum = self.__cluster.get_down_num()
            if downnum > 0:
                self.__reader_use_times = self.__reader_use_times + 1 #使用次数+1
            if downnum and self.__reader_use_times >= self.__retry_connect_times:
                DEBUG_LOG(_fn_,"downnum-use_times",downnum,\
                            self.__reader_use_times)
                self.__up_servers()
                self.__reader_use_times = 0
            #DEBUG_LOG(_fn_,"_reader_use_times",self.__reader_use_times)
            return self.__readers[selnum]
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return None

    #
    #挂掉某个服务器:仅将broken字段设为True,redis上下文不置空
    #
    def __down_server(self,server):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            DEBUG_LOG(_fn_,"start!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
            server.set_broken()
            if server.is_readonly():
                DEBUG_LOG(_fn_,"reader server::start down_u_first")
                self.__cluster.down_u_first()
            key = ':'.join([str(server._host), str(server._port)])
            self.__redis_contexts.pop(key, None)
            DEBUG_LOG(_fn_,"only set broken",server._host,server._port)
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))

    #
    # 重连激活rediscontext
    #
    def active_server(self):
        _fn_ = inspect.currentframe().f_code.co_name
        #判断server可用性
        #重连机制：超过活跃时间,主动重连服务器
        local_time = time.time()
        for reader in self.__readers:
            self.__down_server(reader)
            break
        if (local_time - self.__writer._last_active_time) >= RECONNECT_TIME:
            DEBUG_LOG(_fn_,"writer reconnect!!!!")
            if self.__connect_server(self.__writer)<0:
                self.__down_server(self.__writer)
                ERROR_LOG(_fn_,"active server to reconnect error")
        for reader in self.__readers:
            if (local_time - reader._last_active_time) >= RECONNECT_TIME:
                DEBUG_LOG(_fn_,"reader reconnect!!!!")
                if self.__connect_server(reader)<0:
                    self.__down_server(reader)
                    ERROR_LOG(_fn_,"active reader server to reconnect error")


    #
    # 获取服务器
    #
    def __get_server(self,write):
        _fn_ = inspect.currentframe().f_code.co_name
        try:
            server = redis_server()
            if write:
                server = self.__writer
            else:
                server = self.__select_reader()
            if server is None:
                ERROR_LOG(_fn_,"server is None,write",write)
                return None
            #判断server可用性
            #重连机制：server已经挂了 或者 超过活跃时间
            #          注意重连时,确保redis连接上下文是ping通的
            activetime = time.time() - server._last_active_time
            if server._broken or activetime >= RECONNECT_TIME:
                DEBUG_LOG(_fn_,"reconnect:broken",server._broken)
                DEBUG_LOG(_fn_,"reconnect:active-max",activetime,RECONNECT_TIME)
                if self.__connect_server(server)<0:
                    self.__down_server(server)
                    ERROR_LOG(_fn_,"active server to reconnect error")
                    return None
            return server
        except Exception,e:
            ERROR_LOG(self.__cn__,_fn_,":error",str(e))
            return None


    """
    # function：获取redis_server连接句柄[即可操作任何redis命令的连接句柄]
    # return：  失败抛出异常，成功返回连接句柄
    """
    def get_redis_server(self,write):
        _fn_ = inspect.currentframe().f_code.co_name
        #DEBUG_LOG(_fn_,"start+++++++++++++++++++++++++++++++++")
        # get redis server
        server = self.__get_server(write)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        #DEBUG_LOG(_fn_,"select server",server._host,server._port)
        return server._rediscontext

    """
    # function：redis命令执行工厂函数，至多执行两次命令
    # return：  根据redis命令返回
    """
    def __redisCommand(self,server,command_name,*args,**kwargs):
        _fn_ = inspect.currentframe().f_code.co_name
        #DEBUG_LOG(_fn_,"start+++++++++++++++++++++++++++++++++")
        rediscommand = getattr(server._rediscontext,command_name) 
        retry = RETRY_REDIS_COMMAND_EXECUTE_TIMES
        res = None
        #DEBUG_LOG(_fn_,"command-args",command_name,*args)
        while 1:
            try:
                res = rediscommand(*args,**kwargs)
                #if retry:
                #    raise Exception
                #else:
                #    raise Exception
                #print res,type(res)
            except Exception,e:
                if retry:
                    WARN_LOG(_fn_,"command execute error,retry again!!")
                    retry = retry -1
                    continue
                else:
                    WARN_LOG(_fn_,"command execute broken,raise except!!")
                    raise Exception(str(e))
            else:
                break
        return res


    """
    # function：将内容以strings格式存到cache，且内容不会过期[set]
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def put_to_cache(self,key,val):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # set成功会返回True
            #server._rediscontext.set(key,val)
            self.__redisCommand(server,'set',key,val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[set] cmd error,down server!")


    """
    # function：将内容以strings格式存到cache，且设置内容过期时间[setex]
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def put_to_cache_ex(self,key,val,timeout):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if timeout <= 0:
            raise DM_InputError(_fn_,"args error:timeout<=0")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # setex成功会返回True
            #server._rediscontext.setex(key,val,timeout)
            self.__redisCommand(server,'setex',key,val,timeout)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[setex] cmd error,down server!")


    """
    # function：获取strings格式存储在cache的内容[get]
    # return：  失败抛出异常，成功返回str内容(key不存在返回None)
    """
    def get_from_cache(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #cache不存在返回None
            #str_val = server._rediscontext.get(key)
            str_val = self.__redisCommand(server,'get',key)
            #更新server active_time
            server.active()
            return str_val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[get] cmd error,down server!")


    """
    # function：获取strings格式存储在cache的内容[mget]
    # return：  失败抛出异常，成功返回[v1,v2](key不存在对应位置返回None)
    """
    def get_multi_from_cache(self,*key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #cache不存在返回None
            #vallist = server._rediscontext.mget(*key)
            vallist = self.__redisCommand(server,'mget',*key)
            #更新server active_time
            server.active()
            return vallist
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[get] cmd error,down server!")


    """
    # function：删除cache内容，可批量删除keys[delete]
    # return：  失败抛出异常，成功正常删除且无异常抛出
    """
    def del_from_cache(self,*key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #delete删除成功返回1(只要有一个key存在并删除成功也返回1)
            #key不存在删除时,delete返回False
            #but 函数结果皆保证cache不再存在这些key值
            #server._rediscontext.delete(*key)
            self.__redisCommand(server,'delete',*key)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[delete] cmd error,down server!")


    """
    # function：自增key[incr]
    # return：  失败抛出异常，成功返回自增的int结果值
    """
    def incr_key(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #cache不存在也会自动添加并自增1
            #incr_val = server._rediscontext.incr(key)
            incr_val = self.__redisCommand(server,'incr',key)
            #更新server active_time
            server.active()
            return incr_val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[incr] cmd error,down server!")

    """
    # function：自增key[decr]
    # return：  失败抛出异常，成功返回自增的int结果值
    """
    def decr_key(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #cache不存在也会自动添加并自增1
            #decr_val = server._rediscontext.decr(key)
            decr_val = self.__redisCommand(server,'decr',key)
            #更新server active_time
            server.active()
            return decr_val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[decr] cmd error,down server!")


    """
    # function：增加队列，先进先出[lpush:]
    # return：  失败抛出异常，成功返回队列当前长度
    """
    def push_to_queue(self,key,valist):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if not valist:
            raise DM_InputError(_fn_,"valist is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            qlen = self.__redisCommand(server,'lpush',key,*valist)
            #更新server active_time
            server.active()
            return qlen
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[lpush] cmd error,down server!")

    """
    # function：获取队列的一个值，先进先出[rpop:]
    # return：  失败抛出异常，成功返回出队列的值
    """
    def pop_from_queue(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            qval = self.__redisCommand(server,'rpop',key)
            #更新server active_time
            server.active()
            return qval
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[rpop] cmd error,down server!")

    """
    # function：获取队列长度，先进先出[llen]
    # return：  失败抛出异常，成功返回队列当前长度
    """
    def llen_queue(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            qlen = self.__redisCommand(server,'llen',key)
            #更新server active_time
            server.active()
            return qlen
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[lpush] cmd error,down server!")


    """
    # function：设置key过期[expire]
    # return：  失败抛出异常，成功正常设置过期时间且无异常抛出
    """
    def set_key_expire(self,key,timeout):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #key存在返回True，key不存在返回False即设置不成功
            #val = server._rediscontext.expire(key,timeout)
            val = self.__redisCommand(server,'expire',key,timeout)
            #print val
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[expire] cmd error,down server!")


    """
    # function：将内容以sorted set结构存到cache[zadd]
    # args:     val和score一对,valist和sclist一对，必须成对同时出现
    #            valist:[v1,v2], sclist:[score1,score2]
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def add_to_sorted_set(self,key,val=None,score=None,valist=None,sclist=None):
        _fn_ = inspect.currentframe().f_code.co_name
        #args check
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if (val is not None and score is None) or \
                (score is not None and val is None):
            raise DM_InputError("`val` and `score` must both be specified")
        if (valist is not None and sclist is None) or \
                (sclist is not None and valist is None):
            raise DM_InputError("`valist` and `sclist` must both be specified")
        #get zadd *args
        pieces = []
        if val is not None and score is not None:
            pieces.append(val)
            pieces.append(score)
        if valist is not None and sclist is not None:
            for i in range(len(valist)):
                pieces.append(valist[i])
                pieces.append(sclist[i])
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.zadd(key,n1,s1,n2,s2,n3=s3)
            # zadd成功添加新的name-score会返回成功添加的元素总数
            # n1已经存在，zadd返回0，但是成功更新score分数值
            #val = server._rediscontext.zadd(key,*pieces)
            self.__redisCommand(server,'zadd',key,*pieces)
            #print _fn_,val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zadd] cmd error,down server!")

    """
    # function：计算sorted set结构的元素总数[zcard]
    # return：  失败抛出异常，成功返回元素总数
    """
    def get_num_from_sorted_set(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #zcard(self, name):
            #计算元素总数，key不存在返回0
            #val = server._rediscontext.zcard(key)
            val = self.__redisCommand(server,'zcard',key)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zcard] cmd error,down server!")

    """
    # function：获取sorted set结构的内容[zrange]
    # args:     start偏移位，count获取总数，皆不能小于0
    #            reverse默认按score倒序返回
    # return：  失败抛出异常，成功返回列表结构:[('v1',score1),('v2',score2)]
    """
    def get_from_sorted_set(self,key,start,count,reverse=True):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if start<0 or count<=0:
            raise DM_InputError(_fn_,"start<0 or count<=0")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #注，命令执行的都是取数组下表start-end or start-num之间的元素
            #zrange(self, name, start, end, desc=False, withscores=False,
            #        score_cast_func=float):
            #zrevrange(self, name, start, num, \
            #        withscores=False, score_cast_func=float):
            #val = server._rediscontext.zrange(key,\
            #        start,start+count-1,desc=reverse,withscores=True)
            val = self.__redisCommand(server,'zrange',key,\
                    start,start+count-1,desc=reverse,withscores=True)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zrange] cmd error,down server!")


    """
    # function：获取sorted set结构成员的分数值[zscore]
    # return：  失败抛出异常，成功返回成员的分数值
    """
    def get_score_from_sorted_set(self,key,member):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if not member:
            raise DM_InputError(_fn_,"member is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #def zscore(self, name, value)
            #value不存在返回None, 存在返回浮点型分数值
            #val = server._rediscontext.zscore(key,member)
            val = self.__redisCommand(server,'zscore',key,member)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zscore] cmd error,down server!")


    """
    # function：获取sorted set结构的内容[zrevrangebyscore]
    # args:     startid起始分数，endid结束分数，count总数，三者皆不能<0
    #            reverse默认按score倒序返回
    #            startid=0默认从最大（小[reverse=False]）分数值开始取起
    #            endid=0默认取到最小（大[reverse=False]）分数值
    # return：  失败抛出异常，成功返回列表结构:[('v1',score1),('v2',score2)]
    """
    def get_from_sorted_set_by_score(self,key,startid,endid,count,reverse=True):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if startid<0 or endid<0 or count<=0:
            raise DM_InputError(_fn_,"startid<0 or endid<0 or count<=0")
        if reverse:
            if startid < endid:
                raise DM_InputError(_fn_,"reverse::startid<endid error")
            if startid == 0:
                startid = sys.maxint
            if endid == 0:
                endid = -sys.maxint 
        else:
            if startid > endid:
                raise DM_InputError(_fn_,"asc::startid>endid error")
            if startid == 0:
                startid = -sys.maxint
            if endid == 0:
                endid = sys.maxint 
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            val = []
            if reverse:
                #zrevrangebyscore(self, name, max, min, start=None, num=None,
                #             withscores=False, score_cast_func=float):
                #val = server._rediscontext.zrevrangebyscore(key,\
                #        startid,endid,start=0,num=count,withscores=True)
                val = self.__redisCommand(server,'zrevrangebyscore',key,\
                        startid,endid,start=0,num=count,withscores=True)
                #print _fn_,val,type(val)
            else:
                #zrangebyscore(self, name, min, max, start=None, num=None,
                #      withscores=False, score_cast_func=float):
                #val = server._rediscontext.zrangebyscore(key,\
                #        startid,endid,start=0,num=count,withscores=True)
                val = self.__redisCommand(server,'zrangebyscore',key,\
                        startid,endid,start=0,num=count,withscores=True)
                #print _fn_,val,type(val)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zrevrangebyscore] cmd error,down server!")


    """
    # function：删除sorted set结构的val内容[zrem]
    # args:     删除的元组val
    # return：  失败抛出异常，成功则删除数据且无异常抛出
    """
    def del_from_sorted_set(self,key,*val_args):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #def zrem(self, name, *values):
            #val存在删除返回1，不存在删除返回0，但结果都是保证val不再有
            #val = server._rediscontext.zrem(key,*val_args)
            val = self.__redisCommand(server,'zrem',key,*val_args)
            #print val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zrem] cmd error,down server!")


    """
    # function：通过score删除sorted set结构的val内容[zremrangebyscore]
    # args:     欲删除的分数score
    # return：  失败抛出异常，成功则删除数据且无异常抛出
    """
    def del_from_sorted_set_by_score(self,key,score):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #def zremrangebyscore(self, name, min, max):
            #删除min和max之间的分数对应的vals
            #score存在删除返回1，不存在删除返回0，但结果都是保证score不再有
            #val = server._rediscontext.zremrangebyscore(key,score,score)
            val = self.__redisCommand(server,'zremrangebyscore',key,score,score)
            #print val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[zremrangebyscore] cmd error,down server!")



    """
    # function：将内容以hashes结构存到cache[hset|hmset]
    # args:     field是hash表内的字段名，fieldval是字段值
    #            field和fieldval是一对，两者存在，则使用hset命令
    #            mapping结构：{'f1':v1,'f2':v2}，mapping存在则用hmset且直接忽略field内容
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def put_to_hash_cache(self,key,field=None,fieldval=None,mapping=None):
        _fn_ = inspect.currentframe().f_code.co_name
        #args check
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if (field is not None and fieldval is None) or \
                (fieldval is not None and field is None):
            raise DM_InputError("`field` and `fieldval` must both be specified")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            if mapping:
                # redis.Redis.hmset(key,mapping)
                # hash字段不存在则创建一个并返回True，已经存在则更新val也返回True
                #val = server._rediscontext.hmset(key,mapping)
                self.__redisCommand(server,'hmset',key,mapping)
                #print _fn_,val,type(val)
            else:
                # redis.Redis.hset(key,name,value)
                # hash表或字段不存在则创建一个并返回1，已经存在则更新val返回0
                #val = server._rediscontext.hset(key,field,fieldval)
                self.__redisCommand(server,'hset',key,field,fieldval)
                #print _fn_,val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[hset|hmset] cmd error,down server!")


    """
    # function：获取cache中以hashes结构存储的内容[hmget]
    # args:     field为字段key的元组列表
    # return：  失败抛出异常，成功返回列表类型，
    #            即field值对应的fieldval列表,对应的field不存在返回None
    """
    def get_from_hash_cache(self,key,*field):
        _fn_ = inspect.currentframe().f_code.co_name
        #args check
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.hmget(key,field)
            # 该方式返回的是数组
            #val = server._rediscontext.hmget(key,*field)
            val = self.__redisCommand(server,'hmget',key,*field)
            #print _fn_,val,type(val)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[hmget] cmd error,down server!")


    """
    # function：获取cache中以hashes结构存储的内容[hgetall]
    # return：  失败抛出异常，成功返回列表类型，不存在返回{}
    """
    def get_all_from_hash_cache(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.hgetall(key)
            # 该方式返回的是字典，不存在key则返回空字典{}
            #val = server._rediscontext.hgetall(key)
            val = self.__redisCommand(server,'hgetall',key)
            #print _fn_,val,type(val)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[hgetall] cmd error,down server!")


    """
    # function：删除hashes结构的field内容[hdel]
    # args:     field_args为要删除的field字段元组，即可以多个field同时删除
    # return：  失败抛出异常，成功正常删除数据且无异常抛出
    """
    def del_from_hash_cache(self,key,*field_args):
        _fn_ = inspect.currentframe().f_code.co_name
        #args check
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.hdel(key,name,*field)
            # 字段存在则返回1，不存在返回0
            #val = server._rediscontext.hdel(key,*field_args)
            val = self.__redisCommand(server,'hdel',key,*field_args)
            #print _fn_,val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[hdel] cmd error,down server!")


    """
    # function：将hashes结构的field内容自增[hincrby]
    # args:     field为hash字段，addnum为要自增的步长
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def atom_add_hash_field(self,key,field,addnum=1):
        _fn_ = inspect.currentframe().f_code.co_name
        #args check
        if not key or not field:
            raise DM_InputError(_fn_,"key or field is None")
        if not isinstance(addnum,int):
            raise DM_InputError(_fn_,"addnum must be int type")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.hincrby(key,name,amount=1)
            # 字段存在则返回1，不存在返回0
            #val = server._rediscontext.hincrby(key,field,amount=addnum)
            self.__redisCommand(server,'hincrby',key,field,amount=addnum)
            #print _fn_,val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[hincrby] cmd error,down server!")


    """
    # function：将hashes结构的field内容自增[hincrbyfloat]
    # args:     field为hash字段，addnum为要增加的步长
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def atom_add_hash_field_by_float(self,key,field,addnum=1.0):
        _fn_ = inspect.currentframe().f_code.co_name
        #args check
        if not key or not field:
            raise DM_InputError(_fn_,"key or field is None")
        if not isinstance(addnum,float):
            raise DM_InputError(_fn_,"addnum must be float type")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        print addnum
        # execute command
        try:
            # redis.Redis.hincrby(key,name,amount=1)
            # 字段存在则返回1，不存在返回0
            #val = server._rediscontext.hincrbyfloat(key,field,amount=addnum)
            self.__redisCommand(server,'hincrbyfloat',key,field,amount=addnum)
            #print _fn_,val,type(val)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[hincrbyfloat] cmd error,down server!")



    """
    # function：将内容以set结构存到cache[sadd]
    # return：  失败抛出异常，成功正常写入数据且无异常抛出
    """
    def add_to_set_cache(self,key,*vallist):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.sadd(key,*val)
            # va1已经存在，sadd返回0，否则返回成功加入的val个数
            #val = server._rediscontext.sadd(key,*vallist)
            self.__redisCommand(server,'sadd',key,*vallist)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[sadd] cmd error,down server!")


    """
    # function：删除以set结构存储的cache[srem]
    # return：  失败抛出异常，成功正常删除且无异常抛出
    """
    def del_from_set_cache(self,key,*vallist):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(True)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            # redis.Redis.sren(key,*val)
            # val不存在srem返回0，否则返回成功删除的val个数
            #val = server._rediscontext.srem(key,*vallist)
            self.__redisCommand(server,'srem',key,*vallist)
            #更新server active_time
            server.active()
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[srem] cmd error,down server!")


    """
    # function：获取set结构的内容[smembers]
    # return：  失败抛出异常
    #            成功返回set结构:set(['v1','v2']),不存在返回set([])
    """
    def get_from_set_cache(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #smembers(self, name)
            #val = server._rediscontext.smembers(key)
            val = self.__redisCommand(server,'smembers',key)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[smembers] cmd error,down server!")

    def get_num_from_set(self,key):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            #smembers(self, name)
            #val = server._rediscontext.smembers(key)
            val = self.__redisCommand(server,'scard',key)
            #更新server active_time
            server.active()
            return int(val or 0)
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[scard] cmd error,down server!")


    """
    # function：判断是否set集合中的一员[sismember]
    # return：  失败抛出异常
    #           成功返回False(非集合一员 or key不存在),True(存在成员)
    """
    def is_member_in_set_cache(self,key,val):
        _fn_ = inspect.currentframe().f_code.co_name
        if not key:
            raise DM_InputError(_fn_,"key is None")
        if not val:
            raise DM_InputError(_fn_,"val is None")
        # get redis server
        server = self.__get_server(False)
        if server is None:
            raise DM_RedisError(_fn_,"get redis server error")
        # execute command
        try:
            val = self.__redisCommand(server,'sismember',key,val)
            #更新server active_time
            server.active()
            return val
        except Exception,e:
            self.__down_server(server)
            raise DM_RedisError(_fn_,"[sismember] cmd error,down server!")



if __name__ == '__main__':
    #print "sys.argv len=%d"%(len(sys.argv))
    SET_LOG_KEY("redis")
    #configfile='../97.cache.config'
    configfile='../cache.config'
    _fn_ = "main"
    


    #redis库使用方式#
    DEBUG_LOG("configfile",configfile)
    cacheinterface = PY_Redis_Cache()    
    if cacheinterface.init(configfile) < 0:
        DEBUG_LOG('cacheinterface init err')
        exit(-1)
    cacheinterface.print_server()

    for i in range(1000):
        try:
            print cacheinterface.put_to_cache('a', 'b')
            print cacheinterface.get_from_cache('a')
            print cacheinterface.get_from_cache('a')
            print cacheinterface.get_from_cache('a')
        except Exception as e:
            print e
        time.sleep(10)


    """
    DEBUG_LOG(_fn_,"sleep 5s~~~~~~~~~~~~~~~~~~~~~~~")
    time.sleep(5)

    DEBUG_LOG(_fn_,"===========================激活redis链接")
    try:
        res = cacheinterface.active_server()
    except Exception,e:
        ERROR_LOG(_fn_,str(e))
        exit(-1)
    exit(0)
    """
    DEBUG_LOG(_fn_,"-----------------------1-------------------------")
    res = cacheinterface.decr_key('INCKEY')
    print 'decr:',res, type(res)
    res = cacheinterface.push_to_queue('QUE',[1,2,3,4.0,5.0])
    print "push:", res, type(res)
    for i in range(int(res)):
        res = cacheinterface.pop_from_queue('QUE') 
        print "pop:",i,res,type(res)
        res = cacheinterface.llen_queue("QUE")
        print 'llen:',i,res,type(res)
    exit(0)
        



    DEBUG_LOG(_fn_,"===========================string格式存储测试")
    try:
        res = cacheinterface.put_to_cache('foo1','aa')
        print _fn_,"1.put_to_cache",res,type(res)

        res = cacheinterface.put_to_cache_ex('foo2','bb',600)
        print _fn_,"2.put_to_cache_ex",res,type(res)

        res = cacheinterface.get_from_cache('foo1')
        print _fn_,"3.1、get_from_cache",res,type(res)
        res = cacheinterface.get_from_cache('foo2')
        print _fn_,"3.2、get_from_cache",res,type(res)
        
        reslist = cacheinterface.get_multi_from_cache('foo1','foo2')
        print _fn_,"4.get_multi_from_cache",reslist,type(reslist)

        res = cacheinterface.del_from_cache('foo1')
        print _fn_,"5.del_from_cache",res,type(res)

        reslist = cacheinterface.get_multi_from_cache('foo1','foo2')
        print _fn_,"6.get_multi_from_cache",reslist,type(reslist)
    except Exception,e:
        ERROR_LOG(_fn_,str(e))
        exit(-1)


    DEBUG_LOG(_fn_,"===========================sorted_set格式存储测试")
    c_s_key = "SORTED_SET_TEST" 
    try:
        DEBUG_LOG(_fn_,"-----------------------1-------------------------")
        #增加sorted set格式内容
        res = cacheinterface.add_to_sorted_set(c_s_key,
                valist=[695230,120318,803933,321577,300792,405239,583001],
                sclist=[45,0,100,89,23,55,31])
        print _fn_,"1.add_to_sorted_set",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------2-------------------------")
        #计算sorted set大小
        res = cacheinterface.get_num_from_sorted_set(c_s_key)
        print _fn_,"2.get_num_from_sorted_set",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------3-------------------------")
        #倒序获取数据,根据start-count获取
        res = cacheinterface.get_from_sorted_set(c_s_key,0,10)
        print _fn_,"3.1 desc::get_from_sorted_set",res,type(res)
        #升序获得数据,根据start-count获取
        res = cacheinterface.get_from_sorted_set(c_s_key,0,5,False)
        print _fn_,"3.2 asc::get_from_sorted_set",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------4-------------------------")
        #score::倒序获取数据(包括边界点值也返回，即89和23的分值内容也返回)
        res = cacheinterface.get_from_sorted_set_by_score(c_s_key,89,23,5)
        print _fn_,"4.1 desc::get_from_sorted_set_by_score",res,type(res)
        #score::升序获得数据
        res = cacheinterface.get_from_sorted_set_by_score(c_s_key,23,89,5,False)
        print _fn_,"4.2 asc::get_from_sorted_set_by_score",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------5-------------------------")
        #通过val删除数据
        res = cacheinterface.del_from_sorted_set(c_s_key,120318)
        print _fn_,"5.1 del_from_sorted_set",res,type(res)
        #通过score删除数据
        res = cacheinterface.del_from_sorted_set_by_score(c_s_key,45)
        print _fn_,"5.2 del_from_sorted_set_by_score",res,type(res)
        #删除后获取最终数据
        res = cacheinterface.get_from_sorted_set(c_s_key,0,10)
        print _fn_,"5.3 after_del::get_from_sorted_set",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------6-------------------------")
        res = cacheinterface.get_score_from_sorted_set(c_s_key,300792)
        print _fn_,"6.get_score_from_sorted_set",res,type(res)
    except Exception,e:
        ERROR_LOG(_fn_,str(e))
        exit(-1)
    

    DEBUG_LOG(_fn_,"===========================其他redis命令测试")
    try:
        #设置key过期时间
        res = cacheinterface.set_key_expire(c_s_key,120)
        print _fn_,"1.set_key_expire",res,type(res)
        #自增id
        c_incr_key = "INCR_TEST"
        res = cacheinterface.incr_key(c_incr_key)
        print _fn_,"2.1、incr_key",res,type(res)
        #获取自增id结果
        res = cacheinterface.get_from_cache(c_incr_key)
        print _fn_,"2.2、get_incr_key",res,type(res)
        #直接获取一个redis句柄
        r = cacheinterface.get_redis_server(True)
        if r is None:
            ERROR_LOG(_fn_,"get redis_server error")
            exit(-1)
        r.set('testA','llll')
        print r.get('testA')
    except Exception,e:
        ERROR_LOG(_fn_,str(e))
        exit(-1)


    DEBUG_LOG(_fn_,"===========================hash结构存储测试")
    try:
        c_h_key = "HASH_TEST"
        atom_field = "r-333"
        DEBUG_LOG(_fn_,"-----------------------1-------------------------")
        #hash写入
        res = cacheinterface.put_to_hash_cache(c_h_key,'r-1456121',1)
        print _fn_,"1.1 put_to_hash_cache",res,type(res)
        res = cacheinterface.put_to_hash_cache(c_h_key,'m-1456121',"mask_right")
        print _fn_,"1.2 put_to_hash_cache",res,type(res)
        res = cacheinterface.put_to_hash_cache(c_h_key,\
                            mapping={'r-333':0,"m-333":"mask333"})
        print _fn_,"1.3 put_to_hash_cache",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------2-------------------------")
        # hget单个取方式
        res = cacheinterface.get_from_hash_cache(c_h_key,\
                                        'r-1456121','m-1456121')
        print _fn_,"2.1 get_from_hash_cache",res,type(res)
        res = cacheinterface.get_all_from_hash_cache(c_h_key)
        print _fn_,"2.2 get_all_from_hash_cache",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------3-------------------------")
        res = cacheinterface.del_from_hash_cache(c_h_key,'r-1456121','m-1456121')
        print _fn_,"3. del_from_hash_cache",res,type(res)

        DEBUG_LOG(_fn_,"-----------------------4-------------------------")
        res = cacheinterface.atom_add_hash_field(c_h_key,'r-333',addnum=5)
        print _fn_,"4.1 atom_add_hash_field",res,type(res)
        res = cacheinterface.get_all_from_hash_cache(c_h_key)
        print _fn_,"4.2 after_all::get_all_from_hash_cache",res,type(res)
        #cacheinterface.atom_add_hash_field_by_float('RH:1001','float-333',addnum=1.5)
    except Exception,e:
        ERROR_LOG(_fn_,str(e))
        exit(-1)


    DEBUG_LOG(_fn_,"===========================set结构存储测试")
    try:
        c_set_key = "SET_TEST"
        res = cacheinterface.add_to_set_cache(c_set_key,'a','b','c',1,2,3)
        print _fn_,"1.add_to_set_cache",res,type(res)

        res = cacheinterface.get_from_set_cache(c_set_key)
        print _fn_,"2.get_from_set_cache",res,type(res)

        res = cacheinterface.del_from_set_cache(c_set_key,'a',3,'d')
        print _fn_,"3.del_from_set_cache",res,type(res)

        res = cacheinterface.get_from_set_cache(c_set_key)
        print _fn_,"4. after_all::get_from_set_cache",res,type(res)

        res = cacheinterface.is_member_in_set_cache(c_set_key,'a')
        print _fn_,"5.1. is_member_in_set_cache(not exist)",res,type(res)
    
        res = cacheinterface.is_member_in_set_cache(c_set_key,2)
        print _fn_,"5.2. is_member_in_set_cache(exist)",res,type(res)

        res = cacheinterface.is_member_in_set_cache("ddddddd",'b')
        print _fn_,"5.3. is_member_in_set_cache(no cache key)",res,type(res)
    except Exception,e:
        ERROR_LOG(_fn_,str(e))
        exit(-1)

    exit(0)

